<!DOCTYPE html>
<html lang="zh-CN">
  <head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <meta name="description" content="">
  <meta name="keywords" content="">
  
    <link rel="icon" href="/avatar.jpg">
  
    
  <title>UVA-442 Matrix Chain Multiplication | 科学君的不科学博客</title>
  <link rel="stylesheet" href="/style.css">
  <link rel="stylesheet" href="/lib/jquery.fancybox.min.css">
  <link href="https://maxcdn.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css">
  <script type="text/javascript" src="https://tajs.qq.com/stats?sId=65546304" charset="UTF-8"></script>
  <script>
  (function(){
      var bp = document.createElement('script');
      var curProtocol = window.location.protocol.split(':')[0];
      if (curProtocol === 'https') {
          bp.src = 'https://zz.bdstatic.com/linksubmit/push.js';
      }
      else {
          bp.src = 'http://push.zhanzhang.baidu.com/push.js';
      }
      var s = document.getElementsByTagName("script")[0];
      s.parentNode.insertBefore(bp, s);
  })();
  </script>
</head>

<body>
  <header>
  <div class="header-container">
    <a class='logo' href="/">
      <span>科学君的不科学博客</span>
    </a>
    <ul class="right-header">
      
        <li class="nav-item">
          
            <a href="/" class="item-link">首页</a>
          
        </li>
      
        <li class="nav-item">
          
            <a href="/about" class="item-link">关于</a>
          
        </li>
      
        <li class="nav-item">
          
            <a href="/archives" class="item-link">归档</a>
          
        </li>
      
        <li class="nav-item">
          
            <a href="/tags" class="item-link">标签</a>
          
        </li>
      
        <li class="nav-item">
          
            <a href="/atom.xml" class="item-link">FEED 订阅</a>
          
        </li>
      
    </ul>
  </div>
</header>

  <main id='post'>
  <div class="content">
    <article>
      <section class="content markdown-body">
        <h1>UVA-442 Matrix Chain Multiplication</h1>
        <div class='post-meta'>
          <i class="fa fa-calendar" aria-hidden="true"></i>
          <time>2016年04月28日</time>
          
          | <i class="fa fa-folder-open-o" aria-hidden="true"></i> 
  <div class="article-category">
    <a class="article-category-link" href="/categories/acm/">acm</a>
  </div>



          
          
          |
          
          <i class="fa fa-tags" aria-hidden="true"></i>
          
          
  <a href="/tags/#acm" class='tag'>acm</a>

  <a href="/tags/#栈" class='tag'>栈</a>

  <a href="/tags/#矩阵运算" class='tag'>矩阵运算</a>


          
        </div>
        <h1 id="题目："><a href="#题目：" class="headerlink" title="题目："></a>题目：</h1><p>Matrix Chain Multiplication</p>
<p>Suppose you have to evaluate an expression like A*B*C*D*E where A,B,C,D and E are matrices. Since matrix multiplication is associative, the order in which multiplications are performed is arbitrary. However, the number of elementary multiplications needed strongly depends on the evaluation order you choose.</p>
<p>For example, let A be a 50*10 matrix, B a 10*20 matrix and C a 20*5 matrix. There are two different strategies to compute A*B*C, namely (A*B)*C and A*(B*C).</p>
<p>The first one takes 15000 elementary multiplications, but the second one only 3500.</p>
<p>Your job is to write a program that determines the number of elementary multiplications needed for a given evaluation strategy.</p>
<p>Input Specification</p>
<p>Input consists of two parts: a list of matrices and a list of expressions.</p>
<p>The first line of the input file contains one integer n ( tex2html_wrap_inline28 ), representing the number of matrices in the first part. The next n lines each contain one capital letter, specifying the name of the matrix, and two integers, specifying the number of rows and columns of the matrix.</p>
<p>The second part of the input file strictly adheres to the following syntax (given in EBNF):</p>
<p>SecondPart = Line { Line } <eof> Line = Expression <cr> Expression = Matrix | “(“ Expression Expression “)” Matrix = “A” | “B” | “C” | … | “X” | “Y” | “Z”</cr></eof></p>
<p>Output Specification</p>
<p>For each expression found in the second part of the input file, print one line containing the word “error” if evaluation of the expression leads to an error due to non-matching matrices. Otherwise print one line containing the number of elementary multiplications needed to evaluate the expression in the way specified by the parentheses.</p>
<p>Sample Input</p>
<p>9 A 50 10 B 10 20 C 20 5 D 30 35 E 35 15 F 15 5 G 5 10 H 10 20 I 20 25 A B C (AA) (AB) (AC) (A(BC)) ((AB)C) (((((DE)F)G)H)I) (D(E(F(G(HI))))) ((D(EF))((GH)I))</p>
<p>Sample Output</p>
<p>0 0 0 error 10000 error 3500 15000 40500 47500 15125</p>
<h1 id="代码："><a href="#代码：" class="headerlink" title="代码："></a>代码：</h1><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// oj.cpp : 定义控制台应用程序的入口点。</span></span><br><span class="line"><span class="comment">//</span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">&lt;iostream&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">&lt;utility&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">&lt;stack&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">&lt;string&gt;</span></span></span><br><span class="line"></span><br><span class="line"><span class="keyword">using</span> <span class="keyword">namespace</span> <span class="built_in">std</span>;</span><br><span class="line"></span><br><span class="line"><span class="keyword">typedef</span> pair&lt;<span class="keyword">int</span>, <span class="keyword">int</span>&gt; P;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">int</span> <span class="title">res</span><span class="params">(P &amp;out, P a, P b)</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">    <span class="keyword">if</span> (a.second != b.first)</span><br><span class="line">        <span class="keyword">return</span> <span class="number">-1</span>;</span><br><span class="line">    out.first = a.first;</span><br><span class="line">    out.second = b.second;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">return</span> a.first*a.second*b.second;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">P L[<span class="number">30</span>];</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">int</span> <span class="title">main</span><span class="params">()</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">    ios::sync_with_stdio(<span class="literal">false</span>);</span><br><span class="line">    <span class="built_in">cin</span>.tie();</span><br><span class="line">    <span class="keyword">int</span> N;</span><br><span class="line">    <span class="built_in">cin</span> &gt;&gt; N;</span><br><span class="line">    <span class="keyword">while</span> (N--)</span><br><span class="line">    &#123;</span><br><span class="line">        <span class="keyword">char</span> name;</span><br><span class="line">        <span class="built_in">cin</span> &gt;&gt; name;</span><br><span class="line">        name -= <span class="string">'A'</span>;</span><br><span class="line">        <span class="built_in">cin</span> &gt;&gt; L[name].first &gt;&gt; L[name].second;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="built_in">string</span> expre;</span><br><span class="line">    getline(<span class="built_in">cin</span>, expre);</span><br><span class="line">    <span class="keyword">while</span> (getline(<span class="built_in">cin</span>, expre))</span><br><span class="line">    &#123;</span><br><span class="line">        <span class="keyword">int</span> r = <span class="number">0</span>;</span><br><span class="line">        <span class="built_in">stack</span>&lt;P&gt; S;</span><br><span class="line">        <span class="keyword">for</span> (<span class="keyword">int</span> i = <span class="number">0</span>;i &lt; expre.size();++i)</span><br><span class="line">        &#123;</span><br><span class="line">            <span class="keyword">if</span> (expre[i] == <span class="string">'('</span>)</span><br><span class="line">                <span class="keyword">continue</span>;</span><br><span class="line">            <span class="keyword">if</span> (expre[i] == <span class="string">')'</span>)</span><br><span class="line">            &#123;</span><br><span class="line">                P b = S.top();</span><br><span class="line">                S.pop();</span><br><span class="line">                P a = S.top();</span><br><span class="line">                S.pop();</span><br><span class="line">                P c;</span><br><span class="line">                <span class="keyword">int</span> z = res(c, a, b);</span><br><span class="line">                <span class="keyword">if</span> (z == <span class="number">-1</span>)</span><br><span class="line">                &#123;</span><br><span class="line">                    r = <span class="number">-1</span>;</span><br><span class="line">                    <span class="keyword">break</span>;</span><br><span class="line">                &#125;</span><br><span class="line">                r += z;</span><br><span class="line">                S.push(c);</span><br><span class="line">                <span class="keyword">continue</span>;</span><br><span class="line">            &#125;</span><br><span class="line">            S.push(L[expre[i] - <span class="string">'A'</span>]);</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">if</span> (r == <span class="number">-1</span>)</span><br><span class="line">            <span class="built_in">cout</span> &lt;&lt; <span class="string">"error"</span> &lt;&lt; <span class="built_in">endl</span>;</span><br><span class="line">        <span class="keyword">else</span></span><br><span class="line">            <span class="built_in">cout</span> &lt;&lt; r &lt;&lt; <span class="built_in">endl</span>;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<h1 id="解析-amp-吐槽："><a href="#解析-amp-吐槽：" class="headerlink" title="解析&amp;吐槽："></a>解析&amp;吐槽：</h1><p>一般看起来题目很长的都是水题。注意到底下的算式中每两个需要相乘的矩阵都会放在一个括号中，不会出现(ABC)这样的算式。 因此，每遇到一个右括号就代表要将括号之前的两个矩阵进行矩阵乘法。我们可以使用一个栈来模拟这个过程：</p>
<ul>
<li>当前的字符是右括号 : 抛弃当前字符</li>
<li>当前的字符是矩阵名称 : 将名称表示的矩阵压栈</li>
<li>当前字符是右括号 : 弹出栈中的前两个矩阵，进行乘法运算，将结果压栈</li>
</ul>
<p>由此便可以模拟整个表达式的计算过程。我们可以用一个 pair 来表示矩阵的行数和列数，矩阵乘法的过程请参考《线性代数》。在前面的 res 函数中计算 结果，如果遇到了没法相乘的矩阵就输出 error。这个函数可以计算结果矩阵的行数和列数并返回相乘的总次数。我们只需要将结果加起来就可以得到结果了。 另外，如果表达式只有一个矩阵的话，表达式长度必为 1，直接输出结果 0。</p>

      </section>
      <div class="license">
        <a href="http://creativecommons.org/licenses/by-sa/3.0/" rel="license" target="_blank">
          <img src="http://i.creativecommons.org/l/by-sa/3.0/88x31.png" style="border-width:0"
               alt="Creative Commons License" class="center">
        </a>
      </div>
      <p>
        本作品采用
        <a rel="license" href="https://creativecommons.org/licenses/by-sa/4.0/deed.zh" target="_blank">
          署名-相同方式共享 4.0 国际
        </a>
        进行许可。欢迎转载、使用、重新发布，但务必保留文章署名
        “不科学的科学君” (Liu233w) 与博客链接：
        <a href="https://liu233w.github.io">https://liu233w.github.io</a>
        ，基于本文修改后的作品务必以相同的许可发布。如有任何疑问，请
        <a href="mailto:wwwlsmcom@outlook.com" target="_blank">与我联系</a>
        。
      </p>
    </article>
    
    <!-- disqus 评论框 start -->
    <div class="comment">
      <div id="disqus_thread" class="disqus-thread">
        <i>加载评论框需要翻墙</i>
      </div>
    </div>
    <!-- disqus 评论框 end -->
    
    
    <!-- livere 评论框 start -->
    <div class="comment">
      <div id="lv-container" data-id="city" data-uid="MTAyMC8zNTE5NS8xMTczMA=="></div>
    </div>
    <!-- livere 评论框 end -->
    
  </div>
  <aside>
    
    <div class="toc-container">
      <h1>目录</h1>
      <div class="content">
        <ol class="toc"><li class="toc-item toc-level-1"><a class="toc-link" href="#题目："><span class="toc-number">1.</span> <span class="toc-text">题目：</span></a></li><li class="toc-item toc-level-1"><a class="toc-link" href="#代码："><span class="toc-number">2.</span> <span class="toc-text">代码：</span></a></li><li class="toc-item toc-level-1"><a class="toc-link" href="#解析-amp-吐槽："><span class="toc-number">3.</span> <span class="toc-text">解析&amp;吐槽：</span></a></li></ol>
      </div>
    </div>
    
  </aside>
</main>

<!-- disqus 公共JS代码 -->
<script type="text/javascript">
  /* * * CONFIGURATION VARIABLES * * */
  var disqus_shortname = "liu233w";
  var disqus_identifier = "https://liu233w.github.io/2016/04/28/uva-442.org/";
  var disqus_url = "https://liu233w.github.io/2016/04/28/uva-442.org/";

  isAgent(getDisqus)

  // determine user agent in China
  function isAgent(cb) {
    var url = '//graph.facebook.com/feed?callback=h';
    var xhr = new XMLHttpRequest();
    var called = false;
    xhr.open('GET', url);
    xhr.onreadystatechange = function () {
      if (xhr.readyState === 4 && xhr.status === 200) {
        called = true;
        cb(true);
      }
    };
    xhr.send();
    // timeout 1s, this facebook API is very fast.
    setTimeout(function () {
      if (!called) {
        xhr.abort();
        cb(false)
      }
    }, 1000);
  }

  function getDisqus(isAgent) {
    var dsq = document.createElement('script');
    dsq.type = 'text/javascript';
    dsq.async = true
    dsq.src = '//' + disqus_shortname + '.disqus.com/embed.js';
    (document.getElementsByTagName('head')[0] || document.getElementsByTagName('body')[0]).appendChild(dsq)
  }
</script>
<!-- disqus 公共JS代码 end -->


<script type="text/javascript">
  (function (d, s) {
    var j, e = d.getElementsByTagName(s)[0];

    if (typeof LivereTower === 'function') {
      return;
    }

    j = d.createElement(s);
    j.src = 'https://cdn-city.livere.com/js/embed.dist.js';
    j.async = true;

    e.parentNode.insertBefore(j, e);
  })(document, 'script');
</script>


  <footer>
  <div class="copyright">
    <div>
      &copy; 2019 | Powered by <a href="https://hexo.io" target="_blank">Hexo</a>&nbsp
    </div>
    <div>
      Theme by <a href="https://github.com/lewis-geek/hexo-theme-Aath" target="_blank">Aath</a>
    </div>
  </div>
</footer>


<script src="https://cdn.bootcss.com/jquery/3.2.1/jquery.min.js"></script>
<script src="/lib/in-view.min.js"></script>
<script src="/lib/lodash.min.js"></script>
<script>
  var isDown = true
  var oldY = 0
  inView.offset(50)

  document.body.addEventListener('touchstart', function(){});
  
  window.addEventListener('scroll', _.throttle(e => {
    var currentY = window.scrollY
    if((oldY - currentY) < 0) {
      isDown = true
    } else {
      isDown = false
    }
    oldY = currentY
  }, 250))

  $("article img").each(function() {
      var strA = "<a data-fancybox='gallery' href='" + this.src + "'></a>";
      $(this).wrapAll(strA);
  });

  $('.toc-link').each(function() {
      var href = $(this).attr("href");
      
      inView(href).on('exit', () => {
        if (isDown) {
          handleActive(href)
        }
      })

      inView(href).on('enter', () => {
        if (!isDown) {
          handleActive(href)
        }
      })

      this.onclick = function(e) {
        var pos = $(href).offset().top - 10;
        $("html,body").animate({scrollTop: pos}, 300);
        setTimeout(() => {
          handleActive(href)
        }, 350)
        return false
      }
  })

  function handleActive(href) {
    document.querySelectorAll('.toc-link').forEach(elm => {
      elm.classList.remove('active')
    })
    document.querySelector(".toc [href='"+ href +"']").classList.add('active')
  }
</script>
<script src="/lib/jquery.fancybox.min.js"></script>

<script async src="//dn-lbstatics.qbox.me/busuanzi/2.3/busuanzi.pure.mini.js"></script>

</body>
</html>
